﻿/*
 * syspoll.hpp
 *
 *  Created on: 2016年12月18日
 *      Author: work
 */

#ifndef INCLUDE_DM_OS_SYSPOOL_HPP_
#define INCLUDE_DM_OS_SYSPOOL_HPP_

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <dm/os/mustlock.hpp>
#include <dm/bitmask.hpp>

namespace dm{
namespace os{

template<int Size,typename Te,typename Tkey>
class CSysPool{
	CSysPool( const CSysPool& );
public:
	typedef boost::interprocess::interprocess_mutex mutex_t;
	typedef dm::os::CMustLock<mutex_t> lock_t;

	static inline int maxSize(){
		return Size;
	}

	CSysPool():m_mutex(){
		for( int i=0;i<Size;++i )
			m_mask[i] = 0;
	}

	Te* find_or_alloc( Tkey k ){
		lock_t lock(m_mutex);
		Te* e = find(k);
		if( e==0 ){
			int g = 0;
			int o = 0;
			if( nextNoUsed(g,o) ){
				setUsed(g,o);
				return m_pool + pos(g,o);
			}
		}

		return 0;
	}

	void free( Tkey k ){
		lock_t lock(m_mutex);
		Te* e = find(k);
		if( e!=0 ){
			int p = pos(e);
			setNoUse(group(p),offset(p));
		}
	}

	void free( Te* e){
		lock_t lock(m_mutex);
		int p = pos(e);
		setNoUse(group(p),offset(p));
	}

	int size(){
		lock_t lock(m_mutex);
		int s = 0;
		for( int g=0;g<Size;++g )
			for( int o=0;o<8;++o )
				if( m_mask[g]&(0x01<<o) )
					++s;
		return s;
	}

	Te* start(){
		lock_t lock(m_mutex);
		int g = 0;
		int o = 0;
		if( nextUsed(g,o) )
			return m_pool+pos(g,o);
		else
			return 0;
	}

	Te* next( Te* e ){
		lock_t lock(m_mutex);
		int p = pos(e);
		int g = group(p);
		int o = offset(p);

		if( nextUsed(g,o) )
			return m_pool+pos(g,o);
		else
			return 0;
	}

protected:

	inline int group( const int& p )const{
		return p/8;
	}

	inline int offset( const int& p )const{
		return p%8;
	}

	inline int pos( const Te* e )const{
		return e-m_pool;
	}

	inline int pos( const int& group,const int& offset )const{
		return group * 8 + offset;
	}

	bool nextUsed( int& group,int& offset ){
		for(;group<Size;++group,offset=0 ){
			if( m_mask[group]!=0 ){
				for( ;offset<8;++offset )
					if( m_mask[group]&(0x01<<offset) )
						return true;
			}
		}

		return false;
	}

	bool nextNoUsed( int& group,int& offset ){
		for(;group<Size;++group,offset=0 ){
			if( m_mask[group]!=0xFF ){
				for( ;offset<8;++offset )
					if( (m_mask[group]&(0x01<<offset))==0 )
						return true;
			}
		}

		return false;
	}

	Te* find( Tkey key ){
		int group = 0;
		int offset = 0;

		while( nextUsed(group,offset) ){
			Te* e = m_pool+pos(group,offset);
			if( *e == key )
				return e;
		}

		return 0;
	}

	inline void setUsed( int group,int offset ){
		m_mask[group] |= (0x01<<offset);
	}

	inline void setNoUse( int group,int offset ){
		m_mask[group] &= (0xFF-(0x01<<offset));
	}
private:
	mutex_t m_mutex;
	dm::uint8 m_mask[Size];
	Te m_pool[Size*8];
};

}
}



#endif /* INCLUDE_DM_OS_SYSPOOL_HPP_ */
